\subsection{Cache individual}
\label{sec:ind-cache}

Uma vez que diminuindo a disputa pelo acesso a uma memória partilhada melhora-se a eficiência de uma aplicação \cite{Goeetz2006}, a ideia desta solução é tentar diminuir ao máximo os pontos em que é necessário proceder ao \gls{lock} para a obter acesso exclusivo. Daí surgiu a implementação de um ResultSet que para cada instância criasse uma cópia (normalmente parcial) do result set. O que isto significa é que cada cursor cliente possui cache próprio.

O cache individual possui as seguintes vantagens:
\begin{enumerate}
  \item O acesso ao cache, tanto para leitura como para escrita, é realizado sem restrições, isto é, não há a necessidade obter \gls{lock} sobre o objecto do cache.
  \item Numa situação de cópia parcial do result set diminui-se o número de vezes que se interage com o servidor.
\end{enumerate}

O segundo ponto carece de uma explicação. Imaginemos um cache com capacidade de uma linha, partilhado por alguns threads. 
Um thread T1 está a trabalhar na linha 5 do result set, entretanto T1 deixa de ser o thread em execução, que passa a ser o thread T2 cuja linha do result set é a 10 e que agora terá de ser pedida ao servidor. A troca de thread em execução provoca uma grande quantidade de mensagens trocadas entre o cliente e o servidor, pois cada thread precisa de pedir as linhas em que está a trabalhar. 
E apesar de se ter utilizado um exemplo simples em que o cache tem capacidade de apenas uma linha, caches com capacidades maiores sofrem ainda mais de perda de desempenho (a demonstração e explicação deste fenómeno encontram-se nas secções \ref{sec:rescachecmp} e \ref{sec:discachecmp}, respectivamente). 
Com um cache individual o carregamento do conteúdo do cache é realizado consoante as necessidades individuais do cursor cliente, pelo que se resolve o problema do maior volume de mensagens trocadas entre o cliente e o servidor, porque o cursor cliente tem em cache as linhas em que estava a trabalhar.

O cache individual possui as seguintes desvantagens:
\begin{enumerate}
  \item Replicação da informação; podem existir caches cujo conteúdo seja o mesmo.
  \item A actualização de um dos caches não reflete as alterações nos restantes caches, sendo necessário os cursores pedirem ao servidor os novos dados.
\end{enumerate}

A Figura \ref{fig:cjdbci-overview} apresenta o diagrama de classes da solução com cache individual. Note-se a relação de \emph{1 para 1} entre CursorIndividualCache e ITDSResultSet, que determina o cache como único para cada cursor cliente.

\begin{figure}[H]
  \caption{Diagrama de classes do cursor com cache individual.}
  \label{fig:cjdbci-overview}
  \centering
  \includegraphics[width=8cm]{images/model/cjdbci-overview}
\end{figure}

As classes CursorForwardOnlyReadOnly, CursorForwardOnlyUpdatable, CursorScroll\-ableRead\-Only e CursorScrollableUpdatable implementam um result set do tipo FORWARD\-\_ONLY/READ\_ONLY, ~~FOR\-WARD\_ONLY/UPDATABLE, ~~SCROLLABLE\_SENSITIVE\\/READ\_ONLY e SCROLLABLE\_UPDATABLE, respectivamente. Estas classes reimplementam os métodos que o respectivo result set não suporta, indicando um erro se esses métodos forem invocados.

A classe CursorIndividualCache tem como função adequar a implementação do ResultSet realizada pelo CResultSet à situação de ter um cache individual. A Tabela \ref{tab:indcacheoverride} descreve os métodos que têm de ser reimplementados (\gls{override}) pela classe CursorIndividualCache.

\begin{table}[H]
{\small
  \caption{Métodos reimplementados pela classe CursorIndividualCache.}
  \label{tab:indcacheoverride}
  \centering
  \begin{tabular}{|l|p{13cm}|}
  \hline
  \head{Método} & \head{Explicação}
  \\ \hline
  \texttt{next} & Cada cursor cliente pode mover o cursor do servidor, assim quando um cursor cliente pede ao servidor que mova o seu cursor para o próxima linha ou próximo buffer, a posição inicial pode não ser a correcta para o cursor cliente que faz o pedido. Por isso, o método next é reimplementado para executar um FETCH ABSOLUTE em vez de um FETCH NEXT (a secção \ref{sec:fetchscroll} apresenta uma explicação destes termos).
  \\ \hline
  \texttt{update} & Aqui também existe o problema do cursor do servidor poder estar noutra linha, por isso o RPC sp\_cursor tem que ser invocado com um \emph{optype} igual a ABSOLUTE$|$UPDATE (conjunção de duas opções usando o operador OR) em vez de UPDATE (ver secção \ref{sec:spcursor}). 
Ao efectuar esta alteração do valor de optype o cursor do servidor passa a considerar o argumento \emph{rownum} como sendo o número da linha contando desde o início do result set em vez de contar desde o início do buffer.
  \\ \hline
  \texttt{delete} & A situação é semelhante ao update, mas o valor DELETE do argumento \emph{optype} é substituído por ABSOLUTE$|$DELETE.
  \\ \hline
  \end{tabular}
}
\end{table}
